home *** CD-ROM | disk | FTP | other *** search
- /***************************************************************************
- * *
- * SktSocketUser.m *
- * Copyright 1992 by Nik A Gervae *
- * *
- * One of a set of three Objective-C classes (SktSocketManager, SktSocket, *
- * and SktSocketUser) which implement a convenient interface to Berkeley *
- * stream sockets under NeXTSTEP(r). See the accompanying class *
- * specifications (files with a .rtf or .spec suffix) for further *
- * information. *
- * *
- * NeXTSTEP is a registered trademark of NeXT Computer, Inc. *
- * *
- ****************************************************************************
- * *
- * LICENSE *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation. *
- * *
- * The program and this makefile are distributed in the hope that it will *
- * be useful, but are provided "AS IS" AND WITHOUT ANY WARRANTY; without *
- * any express or implied warranty of MERCHANTABILITY or FITNESS FOR A *
- * PARTICULAR PURPOSE. See the GNU General Public License for more details. *
- * Any use or distribution of the program and documentation must include *
- * appropriate copyrights to acknowledge Nik A. Gervae and the Free *
- * Software Foundation, Inc. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
- * *
- ****************************************************************************
- * *
- * VERSION HISTORY *
- * *
- * Version numbers are simply dates in the form YYYYMMDD. These represent *
- * the date that version was finished. Only significantly changed versions *
- * are reported here, or those versions requiring explanation of changes. *
- * There may be many interim stages between dated versions. *
- * *
- * DateVersion Primary Author Notes *
- * ----------- --------------- -------------------------------------------- *
- * 19920327 Nik A Gervae First released version *
- * 19920723 Nik A Gervae Actually released *
- * *
- ***************************************************************************/
-
- #import <stdio.h>
- #import <string.h>
-
- #import "SktSocketUser.h"
-
-
- typedef struct {
- @defs(SktSocket)
- } sktsocket;
-
- /*
- * Most users will want lines of text.
- */
- #define DFLT_DELIMITER '\n'
-
- /*
- * See +initialize below for info on these.
- */
- typedef char *(*inpToCharFunc)(id self, SEL _cmd, char aChar,
- NXZone *aZone, ...);
- typedef id (*qOutputFunc)(id self, SEL _cmd, const char *output,
- long int length, ...);
- static inpToCharFunc inputToCharInZone;
- static qOutputFunc outputToSocket;
-
- /***************************************************************************
- * *
- * SktReportUserMemError() *
- * *
- * Report appropriately based on whether the process is a server (has an *
- * SktSocketManager), or a client. *
- * *
- ***************************************************************************/
- void SktReportUserMemError(id self, char *message) {
-
- id socket;
-
- socket = [self socket];
-
- if ([socket manager]) {
- [[socket manager] log:message, [self name], [socket socketFd]];
- }
- else if (stderr) {
- fprintf(stderr, message, [self name], [socket socketFd]);
- }
- return;
- }
-
- /***************************************************************************
- * *
- * These are the constant strings used. Feel free to translate them into *
- * your favorite language. Do be sure to keep all the % directives in *
- * place, or change the code that accesses these strings. *
- * *
- ***************************************************************************/
- #define STR_Error "ERROR (%s %d):"
- #define STR_ReallocFatalError STR_Error "zone realloc failed.\n"
- #define STR_MallocFatalError STR_Error "zone malloc failed.\n"
-
-
- @implementation SktSocketUser
-
-
- /***************************************************************************
- * *
- * +initialize *
- * *
- * This method caches the function pointers for the inputToChar:inZone: and *
- * SktSocket's queueOutput:ofLength: methods. Since these methods are *
- * covered by other methods, we want to avoid a message send each time a *
- * cover is used. This way, we only incur the cost of a function call. *
- * Hopefully that's faster. :-) *
- * *
- ***************************************************************************/
- + initialize
- {
- static BOOL initted = NO;
-
- /*
- * Only do this if we're initializing the class itself. Having a
- * subclass do it only resets the static variables, which is a waste.
- */
- if (NO == initted) {
- inputToCharInZone = (inpToCharFunc)
- [self instanceMethodFor:@selector(inputToChar:inZone:)];
- outputToSocket = (qOutputFunc)
- [[SktSocket class] instanceMethodFor:@selector(queueOutput:ofLength:)];
- initted = YES;
- }
- return self;
- }
-
- /***************************************************************************
- * *
- * -initWithSocket: *
- * *
- * THIS IS THE DESIGNATED INITIALIZER FOR THIS CLASS. *
- * *
- * Initializes the user with a particular SktSocket object for its I/O. *
- * Various ivars are set up here. By default, an SktSocketUser strips the *
- * delimiter from its input, and CRLFs after that. An initial empty queue *
- * is allocated, and no queue limit is imposed (0 means no limit). The *
- * delimiter is by default LF, since most often a user will probably be *
- * processing lines of text. Logging of non-error messages is also enabled *
- * by default. *
- * *
- * If you want to be clever, this class, together with the SktSocket class, *
- * fully supports using NULL-terminated strings, so you could use NULL as *
- * the delimiter, provided NULLs can get sent across the connection. *
- * *
- * ERROR CONDITION: If the allocation fails, a message is logged, and nil *
- * is returned. The object will not exist if this method returns nil, so *
- * you should consider a nil return as a fatal condition and exit the *
- * program. *
- * *
- ***************************************************************************/
- - initWithSocket:(SktSocket *)aSocket
- {
- [super init];
-
- zone = [self zone];
- socket = nil;
- [self setSocket:aSocket]; // Helps in subclassing....
-
- doesStrip = YES;
- doesStripCRLF = YES;
-
- inputQueue = (char *)NXZoneMalloc(zone, INQSIZE);
- if (!inputQueue) {
- SktReportUserMemError(self, STR_MallocFatalError);
- return [self free];
- }
-
- queueLength = 0;
- queueLimit = 0; // This means "no limit"
-
- delimiter = DFLT_DELIMITER;
-
- #ifdef DEBUG
- queueLimit = 3; /// Remember to remove this sometime!
- #endif
-
- return self;
- }
-
- /***************************************************************************
- * *
- * -init *
- * *
- * I don't see any reason for this method, but somebody may want to create *
- * a user, and then later set the socket. This is NOT the designated *
- * initializer. It's here to catch idiot code that sends init, which would *
- * otherwise totally bypass the above method. *
- * *
- * This method isn't in the header, and shouldn't be in the header. I want *
- * people to get compiler warnings for trying to send this message, as its *
- * usually the wrong thing to do. *
- * *
- ***************************************************************************/
- - init
- {
- return [self initWithSocket:nil];
- }
-
- /***************************************************************************
- * *
- * -free *
- * *
- * The name says it all. *
- * *
- * Note that you can lose the socket reference if you're not careful. Be *
- * sure to snag it before sending this message. *
- * *
- ***************************************************************************/
- - free
- {
- if (inputQueue) NXZoneFree(zone, inputQueue);
-
- if (socket && self == [socket user]) [socket setUser:nil];
-
- return [super free];
- }
-
- /***************************************************************************
- * *
- * -setDelimiter: *
- * *
- * Sets the character used by -nextInputLine... to determine what a 'line' *
- * is. Characters up to and including this character will be yanked from *
- * the queue (if possible) when nextInputLine... is used. *
- * *
- ***************************************************************************/
- - setDelimiter:(char)aChar;
- {
- delimiter = aChar;
- return self;
- }
-
- /***************************************************************************
- * *
- * -delimiter *
- * *
- * Returns the character used by -nextInputLine... to determine what a *
- * 'line' is. Characters up to and including this character will be yanked *
- * from the queue (if possible) when nextInputLine... is used. *
- * *
- ***************************************************************************/
- - (char)delimiter
- {
- return delimiter;
- }
-
- /***************************************************************************
- * *
- * -setdoesStrip: *
- * *
- * Allows you to set whether the delimiter is removed from the returned *
- * text string when you use inputToChar... or nextInputLine.... *
- * *
- ***************************************************************************/
-
- - setdoesStrip:(BOOL)flag
- {
- doesStrip = flag;
- return self;
- }
-
- /***************************************************************************
- * *
- * -doesStrip *
- * *
- * Returns YES if the delimiter is removed from the returned text string *
- * when you use inputToChar... or nextInputLine..., NO if it's left alone *
- * (poor thing). *
- * *
- ***************************************************************************/
-
- - (BOOL)doesStrip
- {
- return doesStrip;
- }
-
- /***************************************************************************
- * *
- * -setDoesStripCRLF: *
- * *
- * Allows you to set whether CRLFs are removed from the returned text *
- * string when you use inputToChar... or nextInputLine.... If doesStrip is * * also YES, then CRLF stripping is performed in addition to regular *
- * stripping. *
- * *
- ***************************************************************************/
-
- - setDoesStripCRLF:(BOOL)flag
- {
- doesStripCRLF = flag;
- return self;
- }
-
- /***************************************************************************
- * *
- * -doesStripCRLF *
- * *
- * Returns YES if CRLFs are removed from text strings returned by *
- * inputToChar... or nextInputLine.... If doesStrip is also YES, then CRLF *
- * stripping is performed in addition to regular stripping. *
- * *
- ***************************************************************************/
-
- - (BOOL)doesStripCRLF
- {
- return doesStripCRLF;
- }
-
- /***************************************************************************
- * *
- * -setQueueLimit: *
- * *
- * Allows you to limit the number of 'lines' allowed in the queue at any *
- * one time. If queueLimit is positive, then when new data is added to the *
- * queue, the number of delimiters is counted, and if that exceeds *
- * queueLimit, all of the delimited seqments of characters after are blown *
- * away. *
- * *
- ***************************************************************************/
- - setQueueLimit:(long int)limit
- {
- queueLimit = limit;
-
- return self;
- }
-
- /***************************************************************************
- * *
- * -queueLimit *
- * *
- * Returns the number of 'lines' allowed in the queue at any one time. If *
- * queueLimit is positive, then when new data is added to the queue, the *
- * number of delimiters is counted, and if that exceeds queueLimit, all of *
- * the delimited seqments of characters after are blown away. *
- * *
- ***************************************************************************/
- - (long int)queueLimit
- {
- return queueLimit;
- }
-
- /***************************************************************************
- * *
- * -setSocket: *
- * *
- * Sets the SktSocket object used to that supplied. This method also mucks *
- * with the old and new sockets, to properly remove self as the old *
- * socket's user without causing an infinite loop. This is doable with *
- * methods, but the classes are so tightly bound, it's not really worth the *
- * code bulk or cost of a message send. *
- * *
- ***************************************************************************/
- - (SktSocket *)setSocket:(SktSocket *)aSocket
- {
- SktSocket *oldSocket;
-
- oldSocket = socket;
- socket = aSocket;
-
- /*
- * We need to muck with pointers because messaging would cause an
- * infinite loop.
- */
- if (oldSocket) ((sktsocket *)oldSocket)->user = nil;
- if (socket) ((sktsocket *)socket)->user = self;
-
- return oldSocket;
- }
-
- /***************************************************************************
- * *
- * -socket *
- * *
- * Returns the SktSocket object used for I/O. *
- * *
- ***************************************************************************/
- - (SktSocket *)socket
- {
- return socket;
- }
-
- /***************************************************************************
- * *
- * -queueInput:ofLength: *
- * *
- * Adds the provided segment of characters to the end of the input queue. *
- * Beyond that, enforces queue limits. If a queue limit has been set, this *
- * method counts the number of delimiters in the new queue, and blows away *
- * all fully delimited sequences of characters past the first queueLimit *
- * ones. *
- * *
- * ERROR CONDITION: If the reallocation fails, a message is logged, and nil *
- * is returned. The input queue will not exist if this method returns nil, *
- * so you should consider a nil return as a fatal condition and either free *
- * the object, or exit the program. *
- * *
- ***************************************************************************/
- - queueInput:(const char *)input ofLength:(long int)length
- {
- long int fullLength; // the full length of the queue after appending
- char delimiterCache; // the line delimiter (cached for this call)
- long int queueLimitCache;
-
- /*
- * I hope nobody is this stupid.
- */
- if (0 >= length) return self;
-
- /*
- * If there's no input queue, we've got trouble!
- */
- if (!inputQueue) return nil;
-
- /*
- * Cache the delimiter, since we'll be using it a few times.
- */
- delimiterCache = [self delimiter];
- queueLimitCache = [self queueLimit];
-
- /*
- * Find out how much text we're dealing with, check if we need more space,
- * and smash 'em together. Update the length.
- */
- fullLength = queueLength + length;
-
- /*
- * If the queue needs to be bigger, reallocate it. Watch for
- * a fatal error.
- */
- if (malloc_size(inputQueue) <= fullLength) {
-
- inputQueue = (char *)NXZoneRealloc(zone, inputQueue, fullLength);
-
- if (!inputQueue) {
- SktReportUserMemError(self, STR_ReallocFatalError);
- queueLength = 0;
- return nil;
- }
- }
-
- memcpy(inputQueue+queueLength, input, length);
- queueLength = fullLength;
-
- /*
- * Here's the hairy part. If queue limits have been imposed, we
- * do a bunch of stuff:
- */
- if (0 < queueLimitCache) {
-
- long int lastLineEnd; // char of queue beyond last line
- long int lastFrag; // beginning of non-delimited text
- long int segtsInQueue; // # lines waiting to be processed
-
-
- /*
- * 1. Count up how many lines we can add to the queue and record the
- * position of the end.
- */
- for (segtsInQueue = 0, lastLineEnd = 0; lastLineEnd < queueLength;
- lastLineEnd++) {
-
- if (inputQueue[lastLineEnd] == delimiterCache) segtsInQueue++;
- if (segtsInQueue >= queueLimitCache) break;
- }
- lastLineEnd++; // This may be past the buffer; that's OK.
-
- /*
- * 2. Now, if we didn't cover the entire queue, the limit was
- * exceeded. We have to pull some text back, so that any
- * partially complete segments (fragments) can be completed
- * later.
- */
- if (lastLineEnd < queueLength) {
-
- /*
- * 3. Get the start of the last fragment line
- * (line without delimiter).
- */
- for (lastFrag = queueLength; 0 <= lastFrag; lastFrag--) {
- if (delimiterCache == inputQueue[lastFrag]) {
- lastFrag++; // This may be past the buffer; that's OK (we check).
- break;
- }
- }
-
- /*
- * 4. If there are too many lines in the queue, wipe them out,
- * pulling the fragment line over them so it isn't lost.
- * If there is no fragment (lastFrag == queueLength), don't
- * pull anything. Last, update the queue length.
- */
- if (lastLineEnd < queueLength && lastFrag > lastLineEnd) {
- if (lastFrag < queueLength) {
- memmove(inputQueue+lastLineEnd, inputQueue+lastFrag,
- queueLength-lastFrag);
- }
- queueLength = lastLineEnd + queueLength - lastFrag;
- }
-
- } /*if (lastLineEnd < queueLength)*/
-
- } /*if (0 < queueLimitCache)*/
-
- return self;
-
- } /*queueInput:ofLength:*/
-
- /***************************************************************************
- * *
- * -purgeInput *
- * *
- * Marks the queue as empty, and shrinks it if needed. *
- * *
- * ERROR CONDITION: If the reallocation fails, a message is logged, and nil *
- * is returned. The input queue will not exist if this method returns nil, *
- * so you should consider a nil return as a fatal condition and either free *
- * the object, or exit the program. *
- * *
- ***************************************************************************/
- - purgeInput
- {
- queueLength = 0;
-
- /*
- * Reallocate the queue to be the base size. Since the realloc
- * is only shrinking the buffer, this really has no reason ever
- * to fail, but check anyway.
- */
- if (malloc_size(inputQueue) > INQSIZE) {
-
- inputQueue = (char *)NXZoneRealloc(zone, inputQueue, INQSIZE);
-
- if (!inputQueue) {
- SktReportUserMemError(self, STR_ReallocFatalError);
- queueLength = 0;
- return nil;
- }
-
- }
-
- return self;
- }
-
- /***************************************************************************
- * *
- * -queueOutput:ofLength: *
- * *
- * A cover for SktSockets method for queuing output. This should always be *
- * used by the user instead of directly accessing the socket, as this *
- * method may be changed to do special processing on request. *
- * *
- ***************************************************************************/
- - queueOutput:(const char *)output ofLength:(long int)length
- {
- (*outputToSocket)([self socket], @selector(queueOutput:ofLength:),
- output, length);
- return self;
- }
- /***************************************************************************
- * *
- * -queueOutputString: *
- * *
- * A cover for SktSockets method for queuing output. This should always be *
- * used by the user instead of directly accessing the socket, as this *
- * method may be changed to do special processing on request. *
- * *
- ***************************************************************************/
- - queueOutputString:(const char *)aString
- {
- /*
- * Note that this is sent to the *socket*, not to self.
- */
- (*outputToSocket)([self socket], @selector(queueOutput:ofLength:),
- aString, strlen(aString));
- return self;
- }
-
- /***************************************************************************
- * *
- * -queueLength *
- * *
- * Returns the size in bytes of the input queue. *
- * *
- ***************************************************************************/
- - (long int)queueLength
- {
- return queueLength;
- }
-
- /***************************************************************************
- * *
- * getInput:ofLength:orLess: *
- * *
- * Retrieves length characters from the input queue, putting them into the *
- * buffer provided, and returning the actual number of characters retrieved *
- * (it may be less if the queue is shorter than the requested length). If *
- * the orLess: flag is NO, then no input will be retrieved if the full *
- * length specified can't be retrieved, and zero will be returned. *
- * *
- * THIS METHOD DOES NOT, CANNOT, AND SHOULD NOT DO ANY STRIPPING WHATEVER. *
- * *
- * ERROR CONDITION: If the reallocation fails, a message is logged, and -1 *
- * is returned. The input queue will not exist if this method returns -1, *
- * so you should consider a -1 return as a fatal condition and either free *
- * the object, or exit the program. *
- * *
- ***************************************************************************/
- - (long int)getInput:(char *)input ofLength:(long int)length orLess:(BOOL)flag
- {
- long int effectiveLength;
-
- /*
- * I hope nobody is this stupid.
- */
- if (0 >= length) return 0;
-
- /*
- * If there's no input queue, we've got trouble!
- */
- if (!inputQueue) return -1;
-
- effectiveLength = length < queueLength ? length : queueLength;
- if (NO ==flag && effectiveLength < length) return 0;
- memcpy(input, inputQueue, effectiveLength);
-
- if (0 < queueLength-effectiveLength) {
- memmove(inputQueue, inputQueue+effectiveLength,
- queueLength-effectiveLength);
- }
- queueLength -= effectiveLength;
-
- /*
- * If the queue has shrunk to a length signigicantly smaller than
- * its buffer size, reallocate it to be smaller. This really has
- * no reason ever to fail, but check anyway.
- */
- if (queueLength < INQSIZE/2 && malloc_size(inputQueue) > INQSIZE) {
-
- inputQueue = (char *)NXZoneRealloc(zone, inputQueue, INQSIZE);
-
- if (!inputQueue) {
- SktReportUserMemError(self, STR_ReallocFatalError);
- queueLength = 0;
- return -1;
- }
-
- }
-
- return effectiveLength;
- }
-
- /***************************************************************************
- * *
- * -ungetInput:ofLength: *
- * *
- * Use this method to put back a sequence of characters retrieved from the *
- * queue. The sequence of characters should be exactly the same as it was *
- * IN THE QUEUE (not as it was returned), or all bets are off. In *
- * In particular, you should only use this method to put back characters *
- * retrieved with getInput:ofLength:orLess:, as it is the only retrieval *
- * method that is guaranteed not to muck with the queue or the retrieved *
- * characters. *
- * *
- * Especially do NOT use this method to undo the effects of inputToChar... *
- * or nextInputLine.... Those methods may strip from input the very *
- * characters needed to retrieve a proper segment. *
- * *
- * ERROR CONDITION: If the reallocation fails, a message is logged, and nil *
- * is returned. The input queue will not have been restored if this method *
- * returns nil, so you should consider a nil return as a fatal condition *
- * and either free the object, or exit the program. *
- * *
- ***************************************************************************/
- - ungetInput:(char *)input ofLength:(long int)length
- {
- long int fullLength; //
- long int lastLineEnd; // char of queue beyond last line; for queue limits
- long int lastFrag; // beginning of non-newline terminated text
- char *newQueue;
-
- /*
- * I hope nobody is this stupid.
- */
- if (0 >= length) return self;
-
- /*
- * If there's no input queue, we've got trouble!
- */
- if (!inputQueue) return nil;
-
- /*
- * Find out how much text we're dealing with, check if we need more space,
- * and smash 'em together. Update the length.
- */
- fullLength = queueLength + length;
-
- /*
- * Now muck with everything and make it like it should be.
- * Watch for a fatal error.
- */
- newQueue = (char *)NXZoneMalloc(zone, fullLength);
-
- if (!newQueue) {
- SktReportUserMemError(self, STR_MallocFatalError);
- queueLength = 0;
- return nil;
- }
-
- memcpy(newQueue, input, length);
- memcpy(newQueue+length, inputQueue, queueLength);
-
- NXZoneFree(zone, inputQueue);
- inputQueue = newQueue;
- queueLength = fullLength;
-
- return self;
- }
-
- /***************************************************************************
- * *
- * -getAllInput: *
- * *
- * Returns by reference the entire input queue, and returns its length. *
- * *
- * ERROR CONDITION: If the allocation fails, a message is logged, and -1 is *
- * returned. The input queue will not have been restored if this method *
- * returns -1, so you should consider a return of -1 as a fatal condition *
- * and either free the object, or exit the program. *
- * *
- ***************************************************************************/
- - (long int)getAllInput:(char **)queue
- {
- char *newQueue;
- long int oldQueueLength;
-
- if (!queueLength) return 0;
-
- /*
- * If there's no input queue, we've got trouble!
- */
- if (!inputQueue) return -1;
-
- *queue = inputQueue;
- oldQueueLength = queueLength;
- queueLength = 0;
-
- inputQueue = (char *)NXZoneMalloc(zone, INQSIZE);
- if (!inputQueue) {
- SktReportUserMemError(self, STR_MallocFatalError);
- queueLength = 0;
- return -1;
- }
-
- return oldQueueLength;
- }
-
- /***************************************************************************
- * *
- * -inputToChar: *
- * *
- * This method is a cover for -inputToChar:inZone:. It invokes that method *
- * with NXDefaultMallocZone() as the zone argument. *
- * *
- * ERROR CONDITION: If the allocation fails, a message is logged, and NULL *
- * is returned. Since this is indistinguishable from a situation in which *
- * there is nothing in the queue, you can't currently catch a malloc *
- * failure in this method. *
- * *
- ***************************************************************************/
- - (char *)inputToChar:(char)aChar;
- {
- return (char *)(*inputToCharInZone)(self, @selector(inputToChar:inZone:),
- aChar, NXDefaultMallocZone());
- }
-
- /***************************************************************************
- * *
- * -inputToChar:inZone: *
- * *
- * Scans the input queue for the character provided, and pulls characters *
- * from the queue up to and including that character. The characters are *
- * copied to a buffer allocated from the specified zone. Further, if *
- * stripping is enabled, the delimiter is removed from the retrieved *
- * string. If CRLF stripping is enabled, all trailing CRLFs are removed *
- * (after the non-CRLF delimiter is removed if regular stripping is also *
- * enabled). Note that the return value is a NULL-terminated character *
- * string (which may be NULL or empty. *
- * *
- * ERROR CONDITION: If the allocation fails, a message is logged, and NULL *
- * is returned. Since this is indistinguishable from a situation in which *
- * there is nothing in the queue, you can't currently catch a malloc *
- * failure in this method. *
- * *
- ***************************************************************************/
- - (char *)inputToChar:(char)aChar inZone:(NXZone *)aZone;
- {
- char *nextInput;
- long int rest;
- BOOL doesStripCache;
- BOOL doesStripCRLFCache;
-
- /*
- * If there's no input queue, we've got trouble!
- */
- if (!inputQueue) return NULL;
-
- doesStripCache = [self doesStrip];
- doesStripCRLFCache = [self doesStripCRLF];
-
- /*
- * Go to the end of a delimited sequence.
- */
- for (rest = 0; rest < queueLength && inputQueue[rest] != aChar; rest++)
- ;
-
- /*
- * There isn't a delimited sequence. We'll return an empty string.
- * This condition also occurs if the queue is empty.
- */
- if (rest >= queueLength) {
-
- nextInput = (char *)NXZoneMalloc(aZone, 1);
- if (!nextInput) {
- SktReportUserMemError(self, STR_MallocFatalError);
- return NULL;
- }
- nextInput[0] = '\0';
- return nextInput;
- }
- else {
-
- /*
- * We've got a delimited sequence. Go just past aChar, and copy
- * the sequence for return. Mark the string end with '\0'.
- */
- rest++;
-
- nextInput = (char *)NXZoneMalloc(aZone, rest+1);
- if (!nextInput) {
- SktReportUserMemError(self, STR_MallocFatalError);
- return NULL;
- }
- memcpy(nextInput, inputQueue, rest);
- nextInput[rest] = '\0';
- }
-
- /*
- * Do goopy stripping stuff. Check CRLF stripping, only doing so
- * if the delimiter itself is stripped or the string ends in either
- * a CR or an LF.
- */
- if (YES == doesStripCRLFCache) {
- long int tail;
-
- tail = rest-1;
- if (!ISENDLINE(nextInput[tail]) && YES == doesStripCache)
- nextInput[tail--] = '\0';
- for ( ; 0 <= tail && ISENDLINE(nextInput[tail]); tail--)
- nextInput[tail] = '\0';
- }
- else if (YES == doesStripCache) {
- nextInput[rest-1] = '\0';
- }
-
- /*
- * Pull back the queue.
- */
- memmove(inputQueue, inputQueue+rest, queueLength-rest);
- queueLength -= rest;
-
- /*
- * If the queue has shrunk to a significantly smaller size than
- * the queue's allocated block, shrink the block to the minimum size.
- * (We don't want the queue growing without bound! (Not that it will.)
- */
- if (queueLength < INQSIZE/2 && malloc_size(inputQueue) > INQSIZE) {
- inputQueue = (char *)NXZoneRealloc(zone, inputQueue, INQSIZE);
- if (!inputQueue) {
- SktReportUserMemError(self, STR_ReallocFatalError);
- queueLength = 0;
- }
- }
-
- return nextInput;
-
- } /*inputToChar:inZone:*/
-
- /***************************************************************************
- * *
- * -nextInputLine *
- * *
- * This method is a cover for -inputToChar:inZone:, with the user's *
- * delimiter as the ...ToChar: argument, and NXDefaultMallocZone() as the *
- * zone. *
- * *
- * ERROR CONDITION: If the allocation fails, a message is logged, and NULL *
- * is returned. Since this is indistinguishable from a situation in which *
- * there is nothing in the queue, you can't currently catch a malloc *
- * failure in this method. *
- * *
- ***************************************************************************/
- - (char *)nextInputLine
- {
- return (*inputToCharInZone)(self, @selector(inputToChar:inZone:),
- [self delimiter], NXDefaultMallocZone());
- }
-
- /***************************************************************************
- * *
- * -nextInputLineInZone: *
- * *
- * This method is a cover for -inputToChar:inZone:, with the user's *
- * delimiter as the ...ToChar: argument *
- * *
- * ERROR CONDITION: If the allocation fails, a message is logged, and NULL *
- * is returned. Since this is indistinguishable from a situation in which *
- * there is nothing in the queue, you can't currently catch a malloc *
- * failure in this method. *
- * *
- ***************************************************************************/
- - (char *)nextInputLineInZone:(NXZone *)aZone
- {
- return (*inputToCharInZone)(self, @selector(inputToChar:inZone:),
- [self delimiter], aZone);
- }
-
- @end /*implementation SktSocketUser*/
-
- /***************************************************************************
- ***************************************************************************/
-